package yxy.cherry.gateway;

import java.net.InetSocketAddress;
import java.net.SocketAddress;

import yxy.apple.logger.Logger;
import yxy.apple.nio.client.Client;
import yxy.apple.nio.server.Server;
import yxy.apple.util.redisson.FastjsonCodec;
import yxy.apple.util.redisson.RedisConnection;
import yxy.banana.launcher.Reactable;
import yxy.banana.server.external.ExternalServerMapper;
import yxy.banana.server.internal.InternalClientBundler;
import yxy.banana.socket.receiver.Observer;
import yxy.cherry.game.base.bean.GatewayUrl;
import yxy.cherry.game.base.mq.MqManager;
import yxy.cherry.gateway.Configuration.PortalClass;
import yxy.cherry.gateway.external.GatewayServerHandler;
import yxy.cherry.gateway.external.GatewayServerInitializer;
import yxy.cherry.gateway.internal.GatewayClientHandler;
import yxy.cherry.gateway.internal.GatewayClientInitializer;

public class Reactor implements Reactable<Configuration> {

	protected static Logger logger = Logger.create(Reactor.class);

	public static final Reactor instance = new Reactor();

	private Server server = null;

	private InternalClientBundler<GatewayClientHandler> internals = null;

	private ExternalServerMapper<GatewayServerHandler> externals = new ExternalServerMapper<>();

	private RedisConnection redis = new RedisConnection();

	private String url;

	private Reactor() {

	}

	public void shutdown() {
		GatewayUrl.logout(redis(), url);
		if (this.server != null) {
			logger.info("正在关闭网关服务...");
			this.server.stop();
		}

		if (this.internals != null) {
			logger.info("正在关闭与路由中心间的内部连接...");
			this.internals.stop();
		}
		{
			logger.info("正在清理等待回应的事务请求...");
			Observer.shared.clear();
		}
		if (this.redis != null) {
			logger.info("正在关闭redis连接...");
			this.redis.disconnect();
		}
	}

	public void start(Configuration configuration) throws Exception {
		{
			logger.info("正在初始化Redis连接...");
			this.redis.connect(configuration.UserRedis.Address, configuration.UserRedis.Password, configuration.UserRedis.Database, true, new FastjsonCodec());
		}
		{
			logger.info("正在初始化MQ连接...");
			initMQ(configuration);
		}
		{
			logger.info("正在初始化到路由中心的内部连接簇...");
			Client client = new Client(new GatewayClientInitializer(),
					new InetSocketAddress(configuration.InternalClient.RouteCenterIP, configuration.InternalClient.RouteCenterPort),
					configuration.InternalClient.Threads);
			this.internals = new InternalClientBundler<GatewayClientHandler>(client, configuration.InternalClient.ReconnectInterval);
			this.internals().start(configuration.InternalClient.Channels);
		}
		{
			logger.info("正在开启网关服务入口...");
			PortalClass portals[] = configuration.ExternalServer.Portals;
			String localIP = configuration.ExternalServer.LocalIP;
			SocketAddress[] bindings = new SocketAddress[portals.length];
			for (int i = 0; i < portals.length; i++) {
				PortalClass portal = portals[i];
				SocketAddress address = new InetSocketAddress(portal.LocalIP, portal.LocalPort);
				bindings[i] = address;

				boolean ws = portal.WebSocket != null;
				boolean ssl = portal.SSL != null && portal.SSL.Enabled;

				logger.info("绑定%s于%s入口，SSL%s...", address, ws ? "WebSocket" : "TCP", ssl ? "开启" : "关闭");

				if (ws) {
					this.url = String.format("%s://%s:%s/gateway", ssl ? "wss" : "ws", localIP, portal.LocalPort);
					logger.info(url);
					GatewayUrl.regist(redis(), url);
				}
			}
			this.server = new Server(new GatewayServerInitializer(), configuration.ExternalServer.AcceptorThreads, configuration.ExternalServer.WorkThreads);
			this.server.start(bindings);
		}
	}

	private void initMQ(Configuration config) throws Exception {
		MqManager.getInstance().init(config.MqConfig);
	}

	public InternalClientBundler<GatewayClientHandler> internals() {
		return this.internals;
	}

	public ExternalServerMapper<GatewayServerHandler> externals() {
		return this.externals;
	}

	public RedisConnection redis() {
		return redis;
	}
}
